package cn.chengpengper.im.platform.user.application.service.impl;

import cn.chengpengper.im.common.cache.distribute.DistributedCacheService;
import cn.chengpengper.im.common.cache.id.SnowFlakeFactory;
import cn.chengpengper.im.common.domain.jwt.JwtUtils;
import cn.chengpengper.im.platform.common.exception.ImException;
import cn.chengpengper.im.platform.common.jwt.JwtProperties;
import cn.chengpengper.im.platform.common.model.constants.ImPlatformContants;
import cn.chengpengper.im.platform.common.model.dto.LoginDto;
import cn.chengpengper.im.platform.common.model.dto.RegisterDto;
import cn.chengpengper.im.platform.common.model.entity.User;
import cn.chengpengper.im.platform.common.model.enums.HttpCode;
import cn.chengpengper.im.platform.common.model.vo.LoginVo;
import cn.chengpengper.im.platform.common.session.UserSession;
import cn.chengpengper.im.platform.common.utils.BeanUtils;
import cn.chengpengper.im.platform.user.application.service.UserService;
import cn.chengpengper.im.platform.user.domain.service.UserDomainService;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDomainService userDomainService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private DistributedCacheService distributedCacheService;

    @Autowired
    private JwtProperties jwtProperties;

    @Override
    public LoginVo login(LoginDto loginDto) {
        if (Objects.isNull(loginDto)) {
            throw new ImException(HttpCode.PARAMS_ERROR);
        }
        User user = distributedCacheService.queryWithPassThrough(ImPlatformContants.PLATFORM_REDIS_USER_KEY, loginDto.getUserName(), User.class, userDomainService::getUserByUserName, ImPlatformContants.DEFAULT_REDIS_CACHE_EXPIRE_TIME, TimeUnit.MINUTES);
        if (Objects.isNull(user)) {
            throw new ImException(HttpCode.PROGRAM_ERROR, "当前用户不存在");
        }
        if (!passwordEncoder.matches(loginDto.getPassword(), user.getPassword())) {
            throw new ImException(HttpCode.PASSWORD_ERROR);
        }
        // 生成token
        UserSession userSession = BeanUtils.copyProperties(user, UserSession.class);
        assert userSession != null;
        userSession.setUserId(user.getId());
        userSession.setTerminal(loginDto.getTerminal());
        String jsonString = JSON.toJSONString(userSession);
        String accessToken = JwtUtils.sign(user.getId(), jsonString, jwtProperties.getAccessTokenExpireIn(), jwtProperties.getAccessTokenSecret());
        String refreshToken = JwtUtils.sign(user.getId(), jsonString, jwtProperties.getRefreshTokenExpireIn(), jwtProperties.getRefreshTokenSecret());
        return LoginVo.builder()
                .accessToken(accessToken)
                .accessTokenExpiresIn(jwtProperties.getAccessTokenExpireIn())
                .refreshToken(refreshToken)
                .refreshTokenExpiresIn(jwtProperties.getRefreshTokenExpireIn())
                .build();
    }

    @Override
    public void register(RegisterDto registerDto) {
        if (Objects.isNull(registerDto)) {
            throw new ImException(HttpCode.PARAMS_ERROR);
        }
        User user = distributedCacheService.queryWithPassThrough(ImPlatformContants.PLATFORM_REDIS_USER_KEY, registerDto.getUserName(), User.class, userDomainService::getUserByUserName, ImPlatformContants.DEFAULT_REDIS_CACHE_EXPIRE_TIME, TimeUnit.MINUTES);
        if (Objects.nonNull(user)) {
            throw new ImException(HttpCode.USERNAME_ALREADY_REGISTER);
        }

        user = BeanUtils.copyProperties(registerDto, User.class);
        assert user != null;
        user.setId(SnowFlakeFactory.getSnowFlakeFromCache().nextId());
        user.setCreateTime(new Date());
        user.setPassword(passwordEncoder.encode(registerDto.getPassword()));
        userDomainService.saveOrUpdateUser(user);
        log.info("注册用户，用户id:{}，用户名:{},昵称:{}", user.getId(), user.getUserName(), user.getNickName());
    }
}
